---
id: lab8-intro
slug: /labs/lab8
sidebar_position: 1
---

# 8. Обработка и печать числовой матриц

Алиас: `печать матрицы`.

## Цель работы

При выполнении лабораторной работы изучить следующие вопросы:

- создание двухмерных динамических массивов;
- обработка матриц;
- использование файлов для хранения матриц;
- передача двумерных массивов в функцию через параметры;
- форматированный вывод матриц на экран;
- доступ к элементам матрицы через указатели и с помощью индексов;
- освоение технологии структурного программирования.

## Задание

### Часть первая

Создать **динамическую матрицу** $A$ размера $N*M$ и заполнить её следующими значениями:

- все элементы главной диагонали равны $1$;
- элементы, лежащие выше главной диагонали, вычисляются по формуле
 $A_{i,j}=\cfrac{x^i}{(j!)^i}$ , а элементы, лежащие ниже главной диагонали, по формуле $A_{i,j}=\cfrac{(-x)^i}{(j!)^i}$, где $i=1,2,...,N$, $j=1,2,...,M$ и $x=1$.

В зависимости от размера матрицы и ширины поля вывода элемента матрицы, обеспечить удобное для пользователя отображение матрицы на экране (с этим связано одно из требований функции вывода массива).

#### Требования к первой части

Обратите внимание, что для выполнения первой части необходимо создать указанные ниже функции и учесть для них определенные требования:

1. **Универсальная функция выделения памяти для двухмерного динамического массива** размера $N*M$ ($N$ - количество строк, $M$ - количество столбцов).
2. **Функция заполнения матрицы $A$**:
   1. Для вычисления значений элементов матрицы использовать рекуррентные соотношения.
3. **Универсальная функция вывода двухмерного динамического массива** размера $N*M$.
   1. Функция должна быть реализована в самостоятельном модуле `mprinter`: объявление сигнатуры должно находиться в `mprinter.h`, а ее реализация - в `mprinter.c` или `mprinter.cpp` (в зависимости от языка программирования).
   2. Отображение строки массива не должно превышать рекомендуемую длину строки, описанную в [руководстве Google по стилю C++](https://habr.com/ru/post/499944/), а именно не более `80` символов. Рекомендуемое значение задать в виде константы в модуле `mprinter`. Если строка выходит за пределы, то необходимо обеспечить перенос непомещающихся столбцов так, как показано в примере ниже. Учесть, что длина столбцов не имеет ограничений.
   3. Матрица $A$ и другие двухмерные массивы должны передаваться в функцию вывода через параметры.
   4. Функция вывода двумерного массива в качестве аргументов должна принимать признак того, в каком формате распечатывать значения элементов матрицы: в экспоненциальном формате (например, `1.23E+10`) и в формате с фиксированной точкой с точностью `precision`. Заданную точность также передавать в качестве аргумента.
4. **Универсальная функция освобождения памяти**, выделенной для двухмерного динамического массива размера $N*M$.

:::caution

Значения `N`, `M` и `precision` (${N, M, precision} \in \mathbb{Z}$) устанавливается генератором случайных чисел из диапазонов:

- $N \in [8, 15]$;
- $M \in [8, 15]$;
- $precision \in [3, 8]$.

:::

#### Пример вывода двухмерного массива

Ниже представлен пример вывода двухмерного массива $9*14$, с точностью `7` знаков после запятой.

Обратите внимание, что:

1. тут демонстрируется каким образом необходимо переносить столбцы, которые не помещаются в рекомендуемое ограничение на длину строки. Конечный вид вывода определяется исполнителем задания.
2. перенос столбцов может потребоваться несколько раз. Иными словами, если на одной строке помещается `5` столбцов, а в массиве их `14`, то в начале вам необходимо отобразить столбцы с `1` по `5`, затем `6` по `10` и в конце с `11` по `14`. В данном примере это и демонстрируется.

```bash
================================================================================
      1.0000000      1.0000000      0.3333333      0.0833333      0.0166667
      4.0000000      1.0000000      0.1111111      0.0069444      0.0002778
     -8.0000000     -1.0000000      1.0000000      0.0005787      0.0000046
     16.0000000      1.0000000      0.0123457      1.0000000      0.0000001
    -32.0000000     -1.0000000     -0.0041152     -0.0000040      1.0000000
     64.0000000      1.0000000      0.0013717      0.0000003      0.0000000
   -128.0000000     -1.0000000     -0.0004572     -0.0000000     -0.0000000
    256.0000000      1.0000000      0.0001524      0.0000000      0.0000000
   -512.0000000     -1.0000000     -0.0000508     -0.0000000     -0.0000000
--------------------------------------------------------------------------------
      0.0027778      0.0003968      0.0000496      0.0000055      0.0000055
      0.0000077      0.0000002      0.0000000      0.0000000      0.0000055
      0.0000000      0.0000000      0.0000000      0.0000000      0.0000055
      0.0000000      0.0000000      0.0000000      0.0000000      0.0000055
      0.0000000      0.0000000      0.0000000      0.0000000      0.0000055
      1.0000000      0.0000000      0.0000000      0.0000000      0.0000055
     -0.0000000      1.0000000      0.0000000      0.0000000      0.0000055
      0.0000000      0.0000000      1.0000000      0.0000000      0.0000055
     -0.0000000     -0.0000000     -0.0000000      1.0000000      0.0000055
--------------------------------------------------------------------------------
      0.0027778      0.0003968      0.0000496      0.0000055
      0.0000077      0.0000002      0.0000000      0.0000000
      0.0000000      0.0000000      0.0000000      0.0000000
      0.0000000      0.0000000      0.0000000      0.0000000
      0.0000000      0.0000000      0.0000000      0.0000000
      1.0000000      0.0000000      0.0000000      0.0000000
     -0.0000000      1.0000000      0.0000000      0.0000000
      0.0000000      0.0000000      1.0000000      0.0000000
     -0.0000000     -0.0000000     -0.0000000      1.0000000
================================================================================
```

### Часть вторая

Распечатать с помощью разработанной функции, используя **вспомогательный массив указателей на строки**, матрицу размером $B[10][10]$, заданную с помощью оператора описания (**нединамическую**). Значение элементов матрицы $B$ определяется соотношением: $B[i][j]=i*10+j$.

:::info

Обратите внимание, что $A$ - динамическая матрица, а $B$ - нединамическая матрица (задана с помощью оператора описания).

:::

Объясните, как передаются матрицы $A$ и $B$ в функцию вывода матриц на экран.

Вставьте в программу и объясните результаты выполнения операторов для матрицы $B[10][10]$, представленных ниже.

#### C

```cpp
printf("B=%f, B[0]=%f, B[2]=%f", B, B[0], B[2]);
printf("B[0][0]=%f, **B=%f, *B[0]=%f", B[0][0], **B, *B[0]);
printf("*(*(B+1))=%f, *B[1]=%f", *(*(B+1)), *B[1]);
printf("*(B[0]+1)=%f, *(*B+1)=%f", *(B[0]+1), *(*B+1));
printf("B[0][20]=%f, *(B[0]+20)=%f, *B[2]=%f", B[0][20], *(B[0]+20), *B[2]);
```

#### C++

```cpp
cout<<B<<"  "<<B[0]<<"  "<<B[2]<<endl;
cout<<B[0][0]<<"  "<<**B <<"  "<<*B[0]<<endl;
cout<<*(*(B+1))<<"  "<<*B[1]<<endl;
cout<<*(B[0]+1)<<"  " <<*(*B+1)<<endl;
cout<<B[0][20]<<"  "<<*(B[0]+20)<<"  "<<*B[2]<<endl;
```

#### Требования к второй части

Обратите внимание, что:

1. для выполнения второй части необходимо создать указанные ниже функции:
   1. **Функция заполнения нединамической матрицы $B$**.
   2. **Функция получения вспомогательного массива указателей на строки матрицы $B$**.
2. матрицу $B$ необходимо выводить в консоль с помощью вспомогательного массива указателей и разработанной функции вывода из модуля `mprinter`.

## Формат вывода в консоли

:::info

Обратите внимание, что здесь не дается явных указаний того, как должен выглядеть консольный вывод. Тут представлены только требования того, что должно быть отображено в выводе.

:::

В выводе консоли должна быть отображена следующая информация:

1. Значения `N`, `x` и `precision`;
2. Вывод сгенерированной матрицы $A$ в экспоненциальном формате и с заданной точностью;
3. Вывод сгенерированной матрицы $B$ с заданной точностью;
4. Вывод значений для матрицы $B$, которые указаны во второй части задания.

## Указания по выполнению работы

Прежде чем приступать к выполнению задания прочитайте приведенный ниже текст и представленные примеры программ.

### Основные правила работы с двухмерными массивами

1. В массивах, определенных с помощью операторов описания, обе размерности должны быть константами или константными выражениями.
2. Массив хранится по строкам, каждая строка хранится в непрерывной области памяти.
3. Первый индекс всегда представляет собой номер строки, второй – номер столбца. Каждый индекс может изменяться от `0` до значения соответствующей размерности, уменьшенной на единицу.
4. При описании массива можно в фигурных скобках задать начальные значения его элементов.
5. Для выделения динамической памяти под массив, в котором все размерности переменные, используются циклы.

### Освобождение динамической памяти из-под массива

#### C

:::info

Основано на ответе [C: Correctly freeing memory of a multi-dimensional array](https://stackoverflow.com/questions/1733881/c-correctly-freeing-memory-of-a-multi-dimensional-array).

:::

Чтобы освободить память, которая была выделена с помощью `malloc()`, вы просто вызываете `free()` именно тот указатель, который вам был предоставлен `malloc()`.

Итак, для этого кода:

```cpp
int **a = malloc(m * sizeof(int *));
```

вам нужно сопоставление:

```cpp
free(a);
```

и для этой строки:

```cpp
a[i] = malloc(n * sizeof(int));
```

вам нужно сопоставление:

```cpp
free(a[i]);
```

внутри аналогичного цикла.

#### C++

Освобождение динамической памяти из-под массива с любым количеством измерений выполняется с помощью операции `delete [] А`, где `А` – имя массива.

### Рекомендации по порядку создания программы

1. Выбрать тип и способ хранения в программе исходных данных, результатов и промежуточных величин.
2. Записать алгоритм сначала в общем  виде, стремясь разбить его на простую последовательность шагов, а затем детализировать каждый шаг.
3. Написать программу. При написании программы рекомендуется:
   - давать переменным понятные имена;
   - не пренебрегать содержательными комментариями;
   - использовать промежуточную печать вычисляемых величин в удобном формате;
   - при написании вложенных циклов следить за отступами;
   - операторы инициализации накапливаемых в цикле величин задавать непосредственно перед циклом, в котором они вычисляются.
4. Параллельно с написанием программы задать тестовые примеры, которые проверяют все ветви алгоритма и возможные диапазоны значений исходных данных.
5. Исходные данные удобнее формировать в файле (по крайней мере, при отладке), не забывая проверять в программе успешность его открытия.

## Проверка задания

Подготовленная программа для решения задания проверяется вручную преподавателем (визуальный контроль).

## Методический материал

1. [Требования к отчету](RequirementsForReport.md)
2. Примеры программ:
   1. [Создание двухмерных динамических массивов](Examples/CreateMatrix.md)
   2. [Передача многомерного массива в функцию с помощью параметров](Examples/PassMatrix.md)
   3. [Программа сортировки строк матрицы](Examples/SortMatrix.md)
3. Контрольные вопросы:
   1. [Для потока на С](TestQuestion/ForC.md)
   2. [Для потока на С++](TestQuestion/ForCpp.md)
